
import java.io.IOException;
import java.util.Vector;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.GameCanvas;
import net.sourceforge.floggy.persistence.FloggyException;
import net.sourceforge.floggy.persistence.ObjectSet;
import net.sourceforge.floggy.persistence.PersistableManager;

public class Game extends GameCanvas implements LoopSteps, ButtonListener {

    //Velocidades em FPS
    private int[] velocidades;
    //Jogador
    private Player player;
    private Gerador gerador;
    //Display destino
    private final int height;
    private final int width;
    //Barra de status
    private int statush;
    private int rectexternoy;
    private int rectspadding;
    private final int rectinternoy;
    private final int areax;
    private final int areay;
    private final int areaw;
    private final int areah;
    boolean[] acertou;
    private Image imgVida;
    private int loops;
    private float velocidade;
    private Vector contas;
    private Conta contaCorrente;
    //Numero de contas neste nivel
    private int numContas;
    private boolean preenchendo;
    private MainLoop loop;
    private final boolean touch;
    private final int areabotoesh;
    private final Button[] botoes;
    private float areabotoesy;

    protected Game() {
        super(false);

        setFullScreenMode(true);

        touch = hasPointerEvents();

        try {
            imgVida = Image.createImage("/vida.png");
        } catch (IOException e) {
        }

        velocidades = new int[]{15, 20, 25};
        player = new Player();
        gerador = new Gerador();
        height = getHeight();
        width = getWidth();
        areabotoesh = (Conta.DRAW_FONT.getHeight() + 2) * 5;
        statush = 16;
        rectexternoy = statush;
        rectspadding = 4;
        rectinternoy = rectexternoy + 4;
        areax = rectspadding + 1;
        areay = rectinternoy + 1;
        areaw = getWidth() - (rectspadding * 2) - 2;
        areah = height - areabotoesh - statush - (rectspadding * 2) - 2;
        areabotoesy = areah + statush;
        acertou = new boolean[4];
        loops = 100;
        velocidade = areah / loops;
        contas = new Vector(1);
        numContas = 2;
        preenchendo = false;
        loop = new MainLoop(this);

        ButtonConfig conf = new ButtonConfig();
        conf.font = Conta.DRAW_FONT;
        conf.width = 20;
        conf.height = Conta.DRAW_FONT.getHeight() + 2;

        botoes = new Button[13];

        //Gera botoes
        int x = 0;
        int linha = 0;
        int bt = 0;
        for (int i = 0; i < 9; i++) {
            Button bt1 = new Button("" + (i + 1), this, conf);
            bt1.setPosition(x, areabotoesy + (conf.height * linha));
            x += conf.width + 8;
            // if (x > getWidth() - (conf.width + 4)) {
            bt++;
            if (bt >= 3) {
                bt = 0;
                x = 0;
                linha++;
            }
            botoes[i] = bt1;
        }

        Button bt0 = new Button("0", this, conf);
        bt0.w = 20;
        bt0.setPosition(x, areabotoesy + (conf.height * linha));
        botoes[9] = bt0;

        x += bt0.w + 8;

        Button btConf = new Button("Ok", this, conf);
        btConf.w = 20;
        btConf.setPosition(x, areabotoesy + (conf.height * linha));
        botoes[10] = btConf;

        x += btConf.w + 8;

        Button btDel = new Button("←", this, conf);
        btDel.w = Conta.DRAW_FONT.stringWidth(btDel.text) + 2;
        btDel.setPosition(x, areabotoesy + (conf.height * linha));
        botoes[11] = btDel;

        Button btMenu = new Button("Menu", this, conf);
        btMenu.w = Conta.DRAW_FONT.stringWidth(btDel.text) + 2;
        btMenu.setPosition(0, height-btMenu.h);
        btMenu.drawBorder = false;
        botoes[12] = btMenu;
    }

    public void tearDown() {
        //TODO Descarregar dados
        velocidades = null;
        // player = null;
        gerador = null;
        acertou = null;
        contas = null;
        // loop = null;
    }

    public void setup() {
        Conta primeiraConta = gerador.nova(player.getNivel());

//        Gerar posicao x
//        int minx = areax;
//        int maxx = (areax + areaw) - primeiraConta.getWidth();
//        primeiraConta.setPosition(gerador.rand(minx, maxx), areay);
        primeiraConta.setPosition(areax + ((areaw - primeiraConta.getWidth()) / 2), areay);
        contas.addElement(primeiraConta);

        contaCorrente = primeiraConta;

//        renderGraphics();
//        paintScreen();
    }

    public void processLogics() {
        for (int i = 0; i < contas.size(); i++) {
            Conta TempC = (Conta) contas.elementAt(i);
            TempC.move(0, velocidade);
        }

        //TODO Distancia
        int andou = (int) (contaCorrente.getY() - areay);

        int dis = 30;

        if (preenchendo && contas.size() < numContas && andou >= dis) {
            Conta TempC = gerador.nova(player.getNivel());

            TempC.setPosition(areax + ((areaw - TempC.getWidth()) / 2), areay);

            contas.addElement(TempC);

            contaCorrente = (Conta) contas.elementAt(0);
        } else {
            preenchendo = false;
        }

        //MARK Bateu
        int pontoFinal = areay + areah - Conta.DRAW_FONT.getBaselinePosition() - 1;
        if (contaCorrente.getY() >= pontoFinal) {

            player.perdeVida();
            contas.removeElement(contaCorrente);

            if (contas.isEmpty()) {
                preenchendo = true;
            } else {
                contaCorrente = (Conta) contas.elementAt(0);
            }
        }

        if (player.getVidas() < 1) {
            loop.stop();

            GameOver gameOver = new GameOver();

            DMath.getInstance().getDisplay().setCurrent(gameOver);

            gameOver.play(player);

            try {
                PersistableManager.getInstance().delete(player);
            } catch (FloggyException ex) {
                //TODO Falhas ao salvar jogo
            }
        }
    }

    public void renderGraphics() {
        Graphics g = getGraphics();

        //Limpa tela
        g.setColor(0);
        g.fillRect(0, 0, getWidth(), getHeight());

        //Desenha fundo barra de status
        drawBevelRect(g, 0, 0, getWidth(), statush, 0x222222, 0x444444,
                0x666666);

        //Vidas
        for (int i = 0; i < player.getVidas(); i++) {
            g.drawImage(imgVida, 1 + (i * imgVida.getWidth()), 1, 0);
        }

        //Pontos
        int px = getWidth() - g.getFont().stringWidth("" + player.getPontos()) - 2;
        g.setColor(0x00ff30);
        g.drawString("" + player.getPontos(), px, (statush - g.getFont().getHeight()) / 2,
                0);

        //Area jogo
        drawBevelRect(g, 0, rectexternoy, getWidth(), height - statush,
                0x222222, 0x444444, 0x666666);
        drawBevelRect(g, rectspadding, rectinternoy, getWidth()
                - (rectspadding * 2), height - statush - (rectspadding * 2),
                0x666666, 0x000000, 0x222222);

        //Area botoes
        if (touch) {
            Button b;
            for (int i = 0; i < botoes.length; i++) {
                b = botoes[i];
                b.draw(g);
            }
        }

        if (!loop.isPaused()) {
            for (int i = 0; i < contas.size(); i++) {
                Conta TempC = (Conta) contas.elementAt(i);
                TempC.draw(g);
            }
        } else {
            g.drawString("Pausado", areax + ((areaw - Conta.DRAW_FONT.stringWidth("Pausado")) / 2), areay + ((areah - Conta.DRAW_FONT.getHeight()) / 2), 0);
        }
    }

    public void paintScreen() {
        flushGraphics();
    }

    public void start() {
        if (!loop.isRunning()) {
            loop.setDesiredUpdateTime(1000 / 15);
            Thread t = new Thread(loop);
            t.setPriority(10);
            t.start();
        }
    }

    public static void drawBevelRect(Graphics g, int x, int y, int w, int h,
            int cor1, int cor2, int cor3) {
        g.setColor(cor2);
        g.fillRect(x + 1, y + 1, w - 2, h - 2);

        g.setColor(cor3);
        g.drawLine(x, y, x, y + h - 1);
        g.drawLine(x, y, x + w - 1, y);

        g.setColor(cor1);
        g.drawLine(x + w - 1, y, x + w - 1, y + h - 1);
        g.drawLine(x, y + h - 1, x + w - 1, y + h - 1);
    }

    protected void keyPressed(int keyCode) {

        if (loop.isRunning()) {
            contaCorrente.keyPressed(keyCode);
        }

        if (keyCode == KEY_STAR || keyCode == -5) {
            comfirmaConta();
            return;
        }

        if (keyCode == Softkeys.leftSoftKey) {
            showMenu();
        }

        if (keyCode == KEY_POUND) {

            if (!loop.isPaused()) {
                loop.pause();
                renderGraphics();
                paintScreen();
            } else {
                contas.removeElement(contaCorrente);
                preenchendo = true;
            }
        }
    }

    private void showMenu() {
        loop.stop();

        try {
            player.save();
        } catch (FloggyException ex) {
            //TODO Problema ao salvar
        }

        //TODO Substituir por midlet ou display
        DMath.getInstance().getDisplay().setCurrent(new Menu());
    }

    private void comfirmaConta() {
        if (contaCorrente.verfica()) {
            int ganho = 0;

            switch (contaCorrente.tipo) {
                case Conta.SOMAR:
                    acertou[0] = true;
                    ganho = player.getNivel();
                    break;
                case Conta.DIVIDIR:
                    acertou[1] = true;
                    ganho = 3 + player.getNivel();
                    break;
                case Conta.MULTIPLICAR:
                    acertou[2] = true;
                    ganho = 2 + player.getNivel();
                    break;
                case Conta.SUBTRAIR:
                    acertou[3] = true;
                    ganho = 1 + player.getNivel();
                    break;
            }

            if (contaCorrente.getX() < areay + (areah / 2)) {
                ganho += 5;
            }

            player.addPontos(ganho);
//
//           
//            renderGraphics();
//            paintScreen();

            boolean all = acertou[0] && acertou[1] && acertou[2] && acertou[3];

            if (all) {
                player.setVidas(player.getVidas() + 1);
                for (int i = 0; i < acertou.length; i++) {
                    acertou[i] = false;
                }
            }

            if (player.getPontos() > Player.PONTOS_NIVEL_1 && player.getNivel() == 1) {
                player.setNivel(2);
            }

            if (player.getPontos() > Player.PONTOS_NIVEL_2 && player.getNivel() == 2) {
                player.setNivel(3);
            }

            loop.setDesiredUpdateTime(1000 / velocidades[player.getNivel() - 1]);

            try {
                player.save();
            } catch (FloggyException ex) {
                //TODO Problema ao salvar
            }

            contas.removeElement(contaCorrente);

            if (contas.isEmpty()) {
                preenchendo = true;
            } else {
                contaCorrente = (Conta) contas.elementAt(0);
            }

        }
    }

    public void continueGame() {
        PersistableManager pm = PersistableManager.getInstance();

        try {
            ObjectSet result = pm.find(Player.class, null, null);
            this.player = (Player) result.get(0);
        } catch (FloggyException ex) {
            //TODO Problema ao continuar
        }

        start();
    }

    protected void pointerPressed(int x, int y) {
        Button b;
        for (int i = 0; i < botoes.length; i++) {
            b = botoes[i];
            if (b.clicked(x, y)) {
                b.click();
            }
        }
    }

    String num = "0123456789";

    public void buttonClicked(ClickEvent evt) {

        if (evt.text.equals("1")) {
            contaCorrente.keyPressed(KEY_NUM1);
        }
        if (evt.text.equals("2")) {
            contaCorrente.keyPressed(KEY_NUM2);
        }
        if (evt.text.equals("3")) {
            contaCorrente.keyPressed(KEY_NUM3);
        }
        if (evt.text.equals("4")) {
            contaCorrente.keyPressed(KEY_NUM4);
        }
        if (evt.text.equals("5")) {
            contaCorrente.keyPressed(KEY_NUM5);
        }
        if (evt.text.equals("6")) {
            contaCorrente.keyPressed(KEY_NUM6);
        }
        if (evt.text.equals("7")) {
            contaCorrente.keyPressed(KEY_NUM7);
        }
        if (evt.text.equals("8")) {
            contaCorrente.keyPressed(KEY_NUM8);
        }

        if (evt.text.equals("9")) {
            contaCorrente.keyPressed(KEY_NUM9);
        } else if (evt.text.equals("0")) {
            contaCorrente.keyPressed(KEY_NUM0);
        }

        if (evt.text.equals("Ok")) {
            comfirmaConta();
        } else if (evt.text.equals("←")) {
            contaCorrente.keyPressed(-8);
        }else if(evt.text.equals("Menu")){
            showMenu();
        }
        
        
    }
}
